package com.dituo.esac.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dituo.core.exception.DtServerException;
import com.dituo.core.po.UserBasePO;
import com.dituo.core.response.PageResultDTO;
import com.dituo.core.threadlocal.UserBaseThreadLocal;
import com.dituo.core.util.DituoExcelUtil;
import com.dituo.core.util.DituoFileUtil;
import com.dituo.core.util.DituoStringUtil;
import com.dituo.core.util.UuidUtils;
import com.dituo.esac.constant.EsacConstant;
import com.dituo.esac.dto.EsacAppInfoDTO;
import com.dituo.esac.dto.EsacAppPersonDTO;
import com.dituo.esac.dto.EsacCheckDTO;
import com.dituo.esac.dto.EsacCheckSaveDTO;
import com.dituo.esac.dto.EsacCommunityDTO;
import com.dituo.esac.dto.EsacExportDTO;
import com.dituo.esac.dto.EsacImportDTO;
import com.dituo.esac.dto.EsacImportExcelDTO;
import com.dituo.esac.dto.EsacPersonDTO;
import com.dituo.esac.dto.EsacSearchDTO;
import com.dituo.esac.mapper.EsacMapper;
import com.dituo.esac.po.DeviceDayCountPO;
import com.dituo.esac.po.EsacAppInfoPO;
import com.dituo.esac.po.EsacCheckInfoPO;
import com.dituo.esac.po.EsacCheckPO;
import com.dituo.esac.po.EsacCommunityCountPO;
import com.dituo.esac.po.EsacCommunityPO;
import com.dituo.esac.po.EsacDeviceNodePO;
import com.dituo.esac.po.EsacInfoPO;
import com.dituo.esac.po.EsacNodeListPO;
import com.dituo.esac.po.EsacPersonPO;
import com.dituo.esac.po.EsacPersonStatusPO;
import com.dituo.esac.po.EsacTemListPO;
import com.dituo.esac.po.TemperatureDayCountPO;
import com.dituo.esac.service.EsacService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;

import reactor.core.publisher.Mono;

/**
 * 疫情业务逻辑处理类
 * @author wanghao
 * @date 2020-02-12 16:05
 */
@Service
public class EsacServiceImpl implements EsacService {

	@Autowired
	EsacMapper esacMapper;
	
	@Value("${dt.file.uploadFolder}")
    private String path;
	
	@Override
	public PageResultDTO<List<EsacNodeListPO>> listEsacHistoryPage(EsacSearchDTO esacSearchDTO) {
		PageResultDTO<List<EsacNodeListPO>> result = new PageResultDTO<>();
		Page<Object> pageInfo = PageHelper.startPage(esacSearchDTO.getPageNum(), esacSearchDTO.getPageSize());
		List<EsacNodeListPO> historyListPage = esacMapper.getHistoryList(esacSearchDTO);
		result.setTotal(pageInfo.getTotal());
		result.setData(historyListPage);
		return result;
	}

	@Override
	public EsacInfoPO getEsacInfo(String personId) {
		return esacMapper.getEsacInfoById(personId);
	}

	@Override
	public PageResultDTO<List<EsacCheckPO>> listEsacCheckPage(EsacSearchDTO esacSearchDTO) {
		PageResultDTO<List<EsacCheckPO>> result = new PageResultDTO<>();
		Page<Object> pageInfo = PageHelper.startPage(esacSearchDTO.getPageNum(), esacSearchDTO.getPageSize());
		List<EsacCheckPO> historyListPage = esacMapper.getEsacListById(esacSearchDTO);
		result.setTotal(pageInfo.getTotal());
		result.setData(historyListPage);
		return result;
	}

	@Override
	@Transactional
	public String saveEsacCheck(EsacCheckSaveDTO esacCheckSaveDTO) throws DtServerException {
		String result = null;
		try {
			List<EsacCheckDTO> checkList = esacCheckSaveDTO.getCheckList();
			if (null != checkList && checkList.size() > 0) {
				for (EsacCheckDTO esacCheckDTO : checkList) {
			        String checkId = UuidUtils.getClearUUID();
			        esacCheckDTO.setCheckId(checkId);
			        esacMapper.addEsacCheck(esacCheckDTO);
				}
			}
			
			result = EsacConstant.ESAC_SAVE_CHECK_SUCCESS;
		} catch (Exception e) {
			result = EsacConstant.ESAC_SAVE_CHECK_FAIL;
			throw new DtServerException(result);
		} finally {
			
		}
		
		return result;
	}

	@Override
	@Transactional
	public String importEsacInfo(EsacImportDTO esacImportDTO) throws DtServerException {
		String result = null;
		if (null == esacImportDTO.getFile()) {
			result = EsacConstant.ESAC_IMPORT_NOFILE;
			throw new DtServerException(result);
		}
		
		InputStream is = null;
	    String destPath = null;
	    try {
	    	FilePart file = esacImportDTO.getFile();
	    	String originName = file.filename();
	    	String basePath = DituoFileUtil.getUploadImagePath(EsacConstant.ESAC_IMPORT_BASE_PATH, path);
			String fileUuid = UuidUtils.getClearUUID();
			String fileType = originName.substring(originName.lastIndexOf("."));
			destPath = basePath + fileUuid + fileType;
			File destFile = new File(destPath);
			esacImportDTO.getFile().transferTo(destFile);
			is = new FileInputStream(destFile);
			EsacImportExcelDTO esacImportExcelDTO = readEsacInfoExcel(is);
			
	    	importEsacInfoData(esacImportExcelDTO);
	    	
            result = EsacConstant.ESAC_IMPORT_SUCCESS;			
	    } catch (Exception e) {
	    	result = EsacConstant.ESAC_IMPORT_FAIL;
	    	throw new DtServerException(result);
	    } finally {
	    	DituoFileUtil.deleteFile(destPath);
	    	if (null != is) {
	    		try {
					is.close();
				} catch (IOException e) {
					result = EsacConstant.ESAC_IMPORT_FAIL;
			    	throw new DtServerException(result);
				}
	    	}
	    }
	    
		return result;
	}

	private EsacImportExcelDTO readEsacInfoExcel(InputStream is) throws DtServerException {
		EsacImportExcelDTO esacImportExcelDTO = new EsacImportExcelDTO();
		
        Workbook wb = null;
        try {  
            wb = WorkbookFactory.create(is);
            Sheet sheet = wb.getSheetAt(0);
            
            //现在未对excel的格式进行校验，直接按提供的模板定制读取的数据
            //获取小区的信息
            UserBasePO userBase = UserBaseThreadLocal.getUserBase();
            EsacCommunityDTO esacCommunityDTO = new EsacCommunityDTO();
            esacCommunityDTO.setOrgid(userBase.getOrgId());
            Row row3 = sheet.getRow(3);
            String communityName = row3.getCell(1).getStringCellValue();
            communityName = communityName.substring(5);
            esacCommunityDTO.setCommunityName(communityName);
            String totalRooms = row3.getCell(5).getStringCellValue();
            totalRooms = totalRooms.substring(6);
            Integer totalRoom = null;
            if (DituoStringUtil.notEmpty(totalRooms)) {
            	totalRoom = Integer.valueOf(totalRooms.trim());
            }
            esacCommunityDTO.setTotalRoom(totalRoom);
            String isolateRooms = row3.getCell(8).getStringCellValue();
            isolateRooms = isolateRooms.substring(7);
            Integer isolateRoom = null;
            if (DituoStringUtil.notEmpty(isolateRooms)) {
            	isolateRoom = Integer.valueOf(isolateRooms.trim());
            }
            esacCommunityDTO.setIsolateRoom(isolateRoom);
            String reportTime = row3.getCell(12).getStringCellValue();
            reportTime = reportTime.substring(5);
            esacCommunityDTO.setReportTime(reportTime);
            
            Row row5 = sheet.getRow(5);
            String communityAddress = row5.getCell(1).getStringCellValue();
            communityAddress = communityAddress.substring(5);
            esacCommunityDTO.setCommunityAddress(communityAddress);
            String totalUsers = row5.getCell(5).getStringCellValue();
            totalUsers = totalUsers.substring(6);
            Integer totalUser = null;
            if (DituoStringUtil.notEmpty(totalUsers)) {
            	totalUser = Integer.valueOf(totalUsers.trim());
            }
            esacCommunityDTO.setTotalUser(totalUser);
            String isolateUsers = row5.getCell(8).getStringCellValue();
            isolateUsers = isolateUsers.substring(7);
            Integer isolateUser = null;
            if (DituoStringUtil.notEmpty(isolateUsers)) {
            	isolateUser = Integer.valueOf(isolateUsers.trim());
            }
            esacCommunityDTO.setIsolateUser(isolateUser);
            String reportUser = row5.getCell(12).getStringCellValue();
            reportUser = reportUser.substring(4);
            esacCommunityDTO.setReportUser(reportUser);
            
            //获取隔离人员的信息
            List<EsacPersonDTO> esacPersonList = new ArrayList<EsacPersonDTO>();
            //根据模板判断数据的总条数以及要取的cell的个数
            int totalRows = sheet.getPhysicalNumberOfRows();
            for (int i=9; i<=totalRows; i++) {
            	Row row = sheet.getRow(i);
            	if (row == null || DituoStringUtil.isEmpty(getCellValue(row.getCell(2))) || DituoStringUtil.isEmpty(getCellValue(row.getCell(3))) 
            			|| DituoStringUtil.isEmpty(getCellValue(row.getCell(4))) || DituoStringUtil.isEmpty(getCellValue(row.getCell(5)))
            			|| DituoStringUtil.isEmpty(getCellValue(row.getCell(6))) || DituoStringUtil.isEmpty(getCellValue(row.getCell(7)))
            			|| DituoStringUtil.isEmpty(getCellValue(row.getCell(8))) || DituoStringUtil.isEmpty(getCellValue(row.getCell(9)))
            			) {
            		continue;
            	}
            	
            	EsacPersonDTO esacPersonDTO = new EsacPersonDTO();
            	esacPersonDTO.setOrgid(userBase.getOrgId());
            	String buildingNumber = getCellValue(row.getCell(2));
            	if (DituoStringUtil.notEmpty(buildingNumber)) {
            		esacPersonDTO.setBuildingNumber(Short.valueOf(buildingNumber.trim()));
            	}
            	String room = getCellValue(row.getCell(3));
            	if (DituoStringUtil.notEmpty(room)) {
            		esacPersonDTO.setRoom(Short.valueOf(room.trim()));
            	}
            	String personName = getCellValue(row.getCell(4));
            	esacPersonDTO.setPersonName(personName);
            	String idCard = getCellValue(row.getCell(5));
            	esacPersonDTO.setIdCard(idCard);
            	String gender = getCellValue(row.getCell(6));
            	if (EsacConstant.GENDER_MALE.equals(gender)) {
            		esacPersonDTO.setGender((short)1);
            	} else if (EsacConstant.GENDER_FEMALE.equals(gender.trim())) {
            		esacPersonDTO.setGender((short)2);
            	} else {
            		esacPersonDTO.setGender((short)1);
            	}
            	String age = getCellValue(row.getCell(7));
            	if (DituoStringUtil.notEmpty(age)) {
            		esacPersonDTO.setAge(Short.valueOf(age.trim()));
            	}
            	String nativePlace = getCellValue(row.getCell(8));
            	esacPersonDTO.setNativePlace(nativePlace);
            	String houseProperty = getCellValue(row.getCell(9));
            	if (EsacConstant.HOUSE_PROPERTY_ONE.equals(houseProperty)) {
            		esacPersonDTO.setHouseProperty((short)1);
            	} else if (EsacConstant.HOUSE_PROPERTY_TWO.equals(houseProperty)) {
            		esacPersonDTO.setHouseProperty((short)2);
            	} else {
            		esacPersonDTO.setHouseProperty((short)1);
            	}
            	
            	esacPersonList.add(esacPersonDTO);
            }
            
            esacImportExcelDTO.setEsacCommunityDTO(esacCommunityDTO);
            esacImportExcelDTO.setEsacPersonList(esacPersonList);
        } catch (Exception e) {  
        	throw new DtServerException(EsacConstant.ESAC_IMPORT_FILEREAD_FAIL);
        }
        
		return esacImportExcelDTO;
	}
	
	private String getCellValue(Cell cell) {
		String cellValue = "";
        if (null != cell) {
            switch (cell.getCellType()) {
                case NUMERIC: //数字
                	DecimalFormat df = new DecimalFormat("0");  //格式化整数
                    cellValue = df.format(cell.getNumericCellValue());
                    break;
                case STRING: // 字符串
                    cellValue = cell.getStringCellValue();
                    break;
                case BOOLEAN: // Boolean
                    cellValue = cell.getBooleanCellValue() + "";
                    break;
                case FORMULA: // 公式
                    cellValue = cell.getCellFormula() + "";
                    break;
                case BLANK: // 空值
                    cellValue = "";
                    break;
                case ERROR: // 故障
                    cellValue = "非法字符";
                    break;
                default:
                    cellValue = "未知类型";
                    break;
            }
        }
		return cellValue;
	}
	
	private void importEsacInfoData(EsacImportExcelDTO esacImportExcelDTO) {
		//保存小区信息
		EsacCommunityDTO esacCommunityDTO = esacImportExcelDTO.getEsacCommunityDTO();
		String communityName = esacCommunityDTO.getCommunityName();
		EsacCommunityPO esacCommunityPO = esacMapper.getEsacCommunityByName(communityName);
		String communityId = UuidUtils.getClearUUID();
		if (null != esacCommunityPO) {
			esacCommunityDTO.setCommunityId(esacCommunityPO.getCommunityId());
			esacMapper.updateEsacCommunity(esacCommunityDTO);
		} else {
			esacCommunityDTO.setCommunityId(communityId);
			esacMapper.addEsacCommunity(esacCommunityDTO);
		}
		
		//保存隔离人员信息
		List<EsacPersonDTO> esacPersonList = esacImportExcelDTO.getEsacPersonList();
		if (null != esacPersonList && esacPersonList.size() > 0) {
			for (EsacPersonDTO esacPersonDTO : esacPersonList) {
				esacPersonDTO.setCommunityId(esacCommunityDTO.getCommunityId());
				String idCard = esacPersonDTO.getIdCard();
				EsacPersonPO esacPersonPO = esacMapper.getEsacPersonByIdCard(idCard);
				if (null != esacPersonPO) {
					esacPersonDTO.setPersonId(esacPersonPO.getPersonId());
					esacMapper.updateEsacPerson(esacPersonDTO);
				} else {
					esacPersonDTO.setPersonId(UuidUtils.getClearUUID());
					esacMapper.addEsacPerson(esacPersonDTO);
				}
			}
		}
	}

	@Override
	public PageResultDTO<List<EsacTemListPO>> listEsacTemPage(EsacSearchDTO esacSearchDTO) {
		PageResultDTO<List<EsacTemListPO>> result = new PageResultDTO<>();
		Page<Object> pageInfo = PageHelper.startPage(esacSearchDTO.getPageNum(), esacSearchDTO.getPageSize());
		List<EsacTemListPO> historyListPage = esacMapper.getTemHistoryList(esacSearchDTO);
		result.setTotal(pageInfo.getTotal());
		result.setData(historyListPage);
		return result;
	}

	@Override
	public EsacAppInfoDTO getAppInfo(EsacSearchDTO esacSearchDTO) {
	 EsacAppInfoDTO appInfo = new EsacAppInfoDTO();
		List<EsacAppInfoPO> list = esacMapper.getAppHistoryList(esacSearchDTO);
		if (null != list && list.size() > 0) {
			appInfo.setBuildingNumber(list.get(0).getBuildingNumber());
			appInfo.setCommunityAddress(list.get(0).getCommunityAddress());
			appInfo.setCommunityName(list.get(0).getCommunityName());
			appInfo.setHouseProperty(list.get(0).getHouseProperty());
			appInfo.setRoom(list.get(0).getRoom());
			List<EsacAppPersonDTO> appPersonDTOs = new ArrayList<EsacAppPersonDTO>();
			for (int i = 0; i < list.size(); i++) {
				EsacAppPersonDTO appPersonDTO = new EsacAppPersonDTO();
				appPersonDTO.setAge(list.get(i).getAge());
				appPersonDTO.setGender(list.get(i).getGender());
				appPersonDTO.setIdCard(list.get(i).getIdCard());
				appPersonDTO.setNativePlace(list.get(i).getNativePlace());
				appPersonDTO.setPersonId(list.get(i).getPersonId());
				appPersonDTO.setPersonName(list.get(i).getPersonName());
				appPersonDTOs.add(appPersonDTO);
			}
			appInfo.setInfos(appPersonDTOs);
		}
		
		return appInfo;
	}
	
	@Override
	public EsacCommunityCountPO getEsacCommunity(Long orgid) {
		EsacCommunityCountPO countPO = esacMapper.getEsacCommunityByOrgId(orgid);
		if (null != countPO) {
			int totalRoom = countPO.getTotalRoom();
			int totalUser = countPO.getTotalUser();
			int isolateRoom = countPO.getIsolateRoom();
			int isolateUser = countPO.getIsolateUser();
			
			DecimalFormat df = new DecimalFormat("0.0");
			float isolateRoomPercent = (float)isolateRoom/totalRoom;
	        float isolateUserPercent = (float)isolateUser/totalUser;
	        countPO.setIsolateRoomPercent(df.format(isolateRoomPercent*100) + "%");
	        countPO.setIsolateUserPercent(df.format(isolateUserPercent*100) + "%");
		}
		
		return countPO;
	}

	@Override
	public List<EsacPersonStatusPO> getEsacDayPerson(String time, Long orgid) {
		return esacMapper.getEsacDayPerson(time, orgid);
	}

	@Override
	public Map<String,Integer> getEsacWarnCountDay(Long orgid, String roleAreaCode, Integer orgType) {
		Map<String,Integer> map = new TreeMap<String, Integer>();
		LocalDate today = LocalDate.now();
		int days = 7;
		for (int i=1; i<=days; i++) {
			map.put(today.minusDays(i).toString(), (int)0);
		}
		List<DeviceDayCountPO> countPO = esacMapper.getEsacWarnCountDay(orgid, roleAreaCode, orgType);
		if (null != countPO && countPO.size()>0) {
			for (DeviceDayCountPO po : countPO) {
				String day = po.getDay();
				Integer warn = po.getWarn();
				
				map.replace(day, 0, warn);
			}
		}
		
		return map;
	}
	
	@Override
	public PageResultDTO<List<EsacCheckInfoPO>> listEsacTemStatusPage(EsacSearchDTO esacSearchDTO) {
		PageResultDTO<List<EsacCheckInfoPO>> result = new PageResultDTO<>();
		Page<Object> pageInfo = PageHelper.startPage(esacSearchDTO.getPageNum(), esacSearchDTO.getPageSize());
		List<EsacCheckInfoPO> historyListPage = esacMapper.selectEsacCheckList(esacSearchDTO);
		result.setTotal(pageInfo.getTotal());
		result.setData(historyListPage);
		return result;
	}

	@Override
	public List<TemperatureDayCountPO> getEsacTempetWarnCountDay(Long orgId) {
		List<TemperatureDayCountPO> temPos = new ArrayList<TemperatureDayCountPO>();
		LocalDate today = LocalDate.now();
		int days = 7;
		for (int i=1; i<=days; i++) {
			TemperatureDayCountPO temPO = new TemperatureDayCountPO();
			temPO.setDay(today.minusDays(i).toString());
			temPO.setCount(0);
			temPO.setWarn(0);
			temPos.add(temPO);
		}
		List<TemperatureDayCountPO> temperaturePO = esacMapper.getEsacTemWarnCountDay(orgId);
		if (null != temperaturePO && temperaturePO.size()>0) {
			for (TemperatureDayCountPO po : temperaturePO) {
				for (int j=0; j<temPos.size(); j++) {
					if(po.getDay().equals(temPos.get(j).getDay())) {
						temPos.get(j).setCount(po.getCount());
						temPos.get(j).setWarn(po.getWarn());
					}
				}
			}
		}
		return temPos;
	}
	
	@Override
	public PageResultDTO<List<EsacDeviceNodePO>> listEsacDeviceNodePage(EsacExportDTO esacExportDTO) {
		PageResultDTO<List<EsacDeviceNodePO>> result = new PageResultDTO<>();
		Page<Object> pageInfo = PageHelper.startPage(esacExportDTO.getPageNum(), esacExportDTO.getPageSize());
		
		List<EsacDeviceNodePO> nodeListPage = esacMapper.getEsacDeviceNodeList(esacExportDTO);
		/*
		 * if(nodeListPage != null && nodeListPage.size()>0) { for (EsacDeviceNodePO
		 * nodePO : nodeListPage) { Long totalNum =
		 * esacMapper.getEascDeviceWarnNum(nodePO.getEuid());
		 * nodePO.setTotalNum(totalNum); } }
		 */
		result.setTotal(pageInfo.getTotal());
		result.setData(nodeListPage);
		
		return result;
	}


	@Override
	public PageResultDTO<List<EsacDeviceNodePO>> listEsacDeviceHistoryPage(EsacExportDTO esacExportDTO) {
		PageResultDTO<List<EsacDeviceNodePO>> result = new PageResultDTO<>();
		Page<Object> pageInfo = PageHelper.startPage(esacExportDTO.getPageNum(), esacExportDTO.getPageSize());
		
		List<EsacDeviceNodePO> historyListPage = esacMapper.getEsacDeviceHistoryList(esacExportDTO);
		result.setTotal(pageInfo.getTotal());
		result.setData(historyListPage);
		
		return result;
	}
	
	@Override
	public Mono<Void> exportExcel(ServerHttpResponse response, EsacExportDTO esacExportDTO) throws Exception {
		int type = esacExportDTO.getType();
		
		List<EsacDeviceNodePO> list = null;
		if (EsacConstant.DATA_TYPE_NODE == type) {
			list = esacMapper.getEsacDeviceNodeList(esacExportDTO);
		} else if(EsacConstant.DATA_TYPE_ALERT == type || EsacConstant.DATA_TYPE_HISTORY == type) {
			list = esacMapper.getEsacDeviceHistoryList(esacExportDTO);
		}
		
		return DituoExcelUtil.exportExcel(response, EsacConstant.EXPORT_FILE_NAME, EsacConstant.EXPORT_SHEET_NAME, 
				EsacConstant.EXPORT_SHEET_TITLE, EsacConstant.EXPORT_TITLE_ARRAY, EsacConstant.EXPORT_TITLE_FIELD, list);
	}
}
